package biolabs.core

/** Applied to a parent object, picks some of its children. */
trait ChildSelector[Parent, Child] {
	def selectFrom(p: Parent): Iterable[Child]
	def apply(p: Parent) = selectFrom(p)

	def canReplace(p: Parent, rem: List[Child], add: List[Child]): Boolean
	def replace(p: Parent, rem: List[Child], add: List[Child])

	def canAddChild(p: Parent, c: Child) = canReplace(p, Nil, c::Nil)
	def addChild(p: Parent, c: Child) = replace(p, Nil, c::Nil)

	def canRemoveChild(p: Parent, c: Child) = canReplace(p, c::Nil, Nil)
	def removeChild(p: Parent, c: Child) = replace(p, c::Nil, Nil)
}

/** Applied to a parent object, picks some of its children
  * together with their associated information.
  *
  * @tparam A type of information that parent associates with the child.
  */
trait AssociativeChildSelector[Parent, Child, A] {
	def selectFrom(p: Parent): Iterable[(Child, A)]
	def apply(p: Parent) = selectFrom(p)

	def canReplace(p: Parent, rem: List[Child], add: List[(Child, A)]): Boolean
	def replace(p: Parent, rem: List[Child], add: List[(Child, A)])

	def canAddChild(p: Parent, c: Child, a: A) = canReplace(p, Nil, (c, a)::Nil)
	def addChild(p: Parent, c: Child, a: A) = replace(p, Nil, (c, a)::Nil)

	def canRemoveChild(p: Parent, c: Child) = canReplace(p, c::Nil, Nil)
	def removeChild(p: Parent, c: Child) = replace(p, c::Nil, Nil)

	def canReassociate(p: Parent, c: Child, a: A)
	def reassociate(p: Parent, c: Child, a: A)
}

object ChildSelector {

	/** Implicit conversion from associative to plain child selector. */
//	implicit def associativeToPlainSelector[Parent, Child](sel: AssociativeChildSelector[Parent, Child, _]) =
//		new ChildSelector[Parent, Child] {
//			override def selectFrom(p: Parent) = sel.selectFrom(p) map { _._1 }
//		}
}